﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Temperature
{
    public interface ITempView
    {
        string Name { get; set; }
        
        void RefreshView();

    }//end interface ITempView

    public class TempModel
    {
        //CONSTANTS
        public const char KELVIN = 'K';
        public const char CELSIUS = 'C';
        public const char FARENHEIT = 'F';

        private const char _DEFAULT_UNIT = KELVIN;

        private const double KELVIN_ABSOLUTE_OFFSET = 0;
        private const double KELVIN_FREEZING_OFFSET = 0;
        private const double KELVIN_INTERVAL_RATIO = 1;

        private const double CELSIUS_ABSOLUTE_OFFSET = -273.15;
        private const double CELSIUS_FREEZING_OFFSET = 0;
        private const double CELSIUS_INTERVAL_RATIO = 1;

        private const double FARENHEIT_ABSOLUTE_OFFSET = -273.15;
        private const double FARENHEIT_FREEZING_OFFSET = 32;
        private const double FARENHEIT_INTERVAL_RATIO = 1.8;

        private static readonly Dictionary<char,double[]> _UNITS = new Dictionary<char,double[]>()
        {
            {KELVIN, new double[]{KELVIN_ABSOLUTE_OFFSET, KELVIN_FREEZING_OFFSET, KELVIN_INTERVAL_RATIO}},
            {CELSIUS, new double[]{CELSIUS_ABSOLUTE_OFFSET, CELSIUS_FREEZING_OFFSET, CELSIUS_INTERVAL_RATIO}},
            {FARENHEIT, new double[]{FARENHEIT_ABSOLUTE_OFFSET, FARENHEIT_FREEZING_OFFSET, FARENHEIT_INTERVAL_RATIO}}
        };


        //private members
        private double _temp = 0;

        //public members and properties
        public char DefaultUnit {
            get
            {
                return _DEFAULT_UNIT;
            }
            private set
            {
                //if (!_UNITS.ContainsKey(value))
                //    throw new ArgumentException("The unit of measure specified, " + value.ToString() + ", is invalid");
                //_DEFAULT_UNIT = value;
            }
        }//end DefaultUnit


        //public methods
        public double GetTemp(char unit)
        {
            if (!_UNITS.ContainsKey(unit))
                throw new ArgumentException("The unit of measure specified, " + unit.ToString() + ", is invalid");

            return (_temp + _UNITS[unit][0])*_UNITS[unit][2] + _UNITS[unit][1];
        }//end ValueIn(char)

        public void SetTemp(double temp, char unit)
        {
            if (!_UNITS.ContainsKey(unit))
                    throw new ArgumentException("The unit of measure specified, " + unit.ToString() + ", is invalid");
            _temp = ((temp - _UNITS[unit][1])/_UNITS[unit][2])-_UNITS[unit][0];
        }//end SetTemp(double,char)
        
    }//end class TempModel

    public class TempController
    {
        private TempModel _model;
        private HashSet<ITempView> _views = new HashSet<ITempView>();

        public TempController(TempModel model)
        {
            if(model != null)
                _model = model;
            else
                throw new ArgumentNullException("The controller must be initialized with a non-null TempModel instance");
        }

        public void RegisterView(ITempView view)
        {
            _views.Add(view);
        }//end RegisterView

        public void UnregisterView(ITempView view)
        {
            _views.Remove(view);
            if (_views.Count == 0)
                System.Windows.Forms.Application.Exit();
        }//end UnregisterView

        public char GetDefaultUnit()
        {
            return _model.DefaultUnit;
        }//end GetDefaultUnit()

        public void SetTemp(double newTemp, char unit)
        {
            _model.SetTemp(newTemp, unit);
            foreach (var view in _views)
                view.RefreshView();
        }//end SetTemp

        public double GetTemp(char unit)
        {
            return _model.GetTemp(unit);
        }//end GetTemp


    }//end class TempController


}
